# coding: u8
import colorsys
import math
import os
import subprocess
import sys
import time

from PIL import ImageDraw, ImageFont, Image


def rgb_to_hsv(r, g, b, a=255):
    h, s, v = colorsys.rgb_to_hsv(r / 255., g / 255., b / 255.)
    return int(h * 255.), int(s * 255.), int(v * 255.)


def is_same_color(h, s, v, bg_hsv):
    bg_h, bg_s, bg_v = bg_hsv
    return (abs(h - bg_h) < 20) and (abs(s - bg_s) < 20)


class AnalyzeImg(object):

    def __init__(self, im, hero_color=(56, 56, 97, 255), ref_coefficient=None):
        self.im = im
        self.w, self.h = self.im.size
        self.draw = ImageDraw.Draw(self.im)
        self.font = ImageFont.truetype("/Library/Fonts/Courier New.ttf", 40, encoding="unic")  # 设置字体
        self.pixels = self.im.load()
        self.hero_color = hero_color
        self.ref_coefficient = ref_coefficient

    def do_analyze(self):
        # 找起点的小人
        start = self.find_hero()
        print "Start:", start

        # 起点在左半屏还是右半屏
        is_hero_on_left = start[0] < self.w / 2
        # 提取背景色
        bg_hsv = rgb_to_hsv(*self.pixels[10, 800])

        # 找目标块
        top_most, lr_most = self.find_most(start, is_hero_on_left, bg_hsv)
        print 'top most pos：', top_most
        print 'left/right most pos', lr_most

        end = top_most[0], lr_most[1]
        print 'center pos', end

        distance = self.get_distance(start, end)
        press_time = self.get_press_time(distance)
        return start, end, top_most, lr_most, distance, press_time

    def find_hero(self):
        hero_poses = []
        for y in xrange(self.h / 3, self.h * 2 / 3):
            for x in xrange(self.w):
                # is purple
                if self.pixels[x, y] == self.hero_color:
                    hero_poses.append((x, y))
        # calc the avg pos
        return tuple(map(lambda i: sum(i) / len(i), zip(*hero_poses)))

    def find_most(self, start, is_hero_on_left, bg_hsv):
        hero_r = 15
        if is_hero_on_left:
            # top most is on the right, scan from right
            from_x = self.w - 1
            to_x = start[0] + hero_r
            step = -1
        else:
            # top most is on the left, scan from left
            from_x = 0
            to_x = start[0] - hero_r
            step = 1

        from_y, to_y = self.h / 4, start[1]

        top_most = self.find_top_most(bg_hsv, from_x, to_x, from_y, to_y, step)
        lr_most = self.find_lr_most(bg_hsv, from_x, to_x, from_y, to_y, step)
        return tuple(top_most), tuple(lr_most)

    def find_top_most(self, bg_hsv, from_x, to_x, from_y, to_y, step):
        for y in xrange(from_y, to_y):
            for x in xrange(from_x, to_x, step):
                h, s, v = rgb_to_hsv(*self.pixels[x, y])
                if not is_same_color(h, s, v, bg_hsv):
                    return x, y

    def find_lr_most(self, bg_hsv, from_x, to_x, from_y, to_y, step):
        for x in xrange(from_x, to_x, step):
            for y in xrange(from_y, to_y):
                h, s, v = rgb_to_hsv(*self.pixels[x, y])
                if not is_same_color(h, s, v, bg_hsv):
                    return x, y

    def get_distance(self, start, center_pos):
        return int(math.sqrt(
            pow(center_pos[0] - start[0], 2) + \
            pow(center_pos[1] - start[1], 2)
        ))

    def get_press_time(self, distance):
        _press_time = distance * 1.45 if distance > 550 else distance * 1.5
        press_time1 = min(950, max(_press_time, 300))
        # 自己的修正系数
        press_time2 = distance * self.ref_coefficient
        return int(math.ceil((press_time1 + press_time2) / 2))


class DrawHelper(object):

    def __init__(self, im):
        self.im = im
        self.w, self.h = self.im.size
        self.draw = ImageDraw.Draw(self.im)
        self.font = ImageFont.truetype("/Library/Fonts/Courier New.ttf", 40, encoding="unic")  # 设置字体

    def draw_pos(self, (x, y), r=3, color=(0, 0, 0)):
        self.draw.line((x, 0, x, self.h), fill=(255, 0, 128))
        self.draw.line((0, y, self.h, y), fill=(128, 0, 255))
        self.draw.ellipse((x - r, y - r, x + r, y + r), fill=color)
        self.draw_text((x - 150, y + 20), "({x}, {y})".format(x=x, y=y))

    def draw_text(self, (x, y), text):
        self.draw.text((x, y), text, (0, 0, 255), self.font)

    def draw_line(self, start, end):
        self.draw.line(start + end, fill=2, width=3)


def debug_info_save(draw, start, center_pos, top_most, lr_most, distance, press_time,
                    screenshot_backup_dir="./screenshot_backups/"):
    # 图上画起止点
    draw.draw_pos(start)
    draw.draw_pos(center_pos)
    draw.draw_line(start, center_pos)
    # 查找过程中的辅助点
    draw.draw_pos(top_most)
    draw.draw_pos(lr_most)
    # 识别出来的距离及需要按压的时间
    draw.draw.text((50, 20), u'Distance:{d}'.format(d=distance), (0, 0, 255), draw.font)
    draw.draw.text((50, 70), u'PressTime:{d}'.format(d=press_time), (0, 0, 255), draw.font)
    draw.im.save('{}{}_d.png'.format(screenshot_backup_dir, int(time.time())))


def pull_and_open_screenshot():
    process = subprocess.Popen('adb shell screencap -p', shell=True, stdout=subprocess.PIPE)
    screenshot = process.stdout.read()
    if sys.platform == 'win32':
        screenshot = screenshot.replace(b'\r\n', b'\n')
    with open('autojump.png', 'wb') as f:
        f.write(screenshot)
    return Image.open('./autojump.png')


def jump(press_time, swipe=None):
    if swipe is None:
        swipe = {'x1': 320, 'y1': 410, 'x2': 320, 'y2': 410}
    cmd = 'adb shell input swipe {x1} {y1} {x2} {y2} {duration}'.format(
        x1=swipe['x1'],
        y1=swipe['y1'],
        x2=swipe['x2'],
        y2=swipe['y2'],
        duration=press_time
    )
    print(cmd)
    os.system(cmd)


if __name__ == '__main__':
    ref_coefficient = 755 / 519.615242271
    debug = True
    while True:
        try:
            im = pull_and_open_screenshot()
            analyze_result = AnalyzeImg(im, ref_coefficient=ref_coefficient).do_analyze()
            if debug:
                draw = DrawHelper(im)
                debug_info_save(draw, *analyze_result)
            jump(analyze_result[len(analyze_result) - 1])
        except KeyboardInterrupt:
            raise
        except Exception as e:
            import traceback
            traceback.print_exc()
            jump(200)
        finally:
            time.sleep(4.5)
